/**
 *  X86Register.java : IceBird project
 *  13:44:54 
 */
package icebird.compiler.ncomp;

import java.util.HashMap;

/**
 * Represents X86 register.
 * 
 * @author Sergey Shulepoff[Knott]
 */
public class X86Register {

	private static HashMap<String, X86Register> map = new HashMap<String, X86Register>();
	
    /* 8-bit GPR registers */
    public static final GPR8 AL = new GPR8("al");
    public static final GPR8 BL = new GPR8("bl");
    public static final GPR8 CL = new GPR8("cl");
    public static final GPR8 DL = new GPR8("dl");
    public static final GPR8 AH = new GPR8("ah");
    public static final GPR8 BH = new GPR8("bh");
    public static final GPR8 CH = new GPR8("ch");
    public static final GPR8 DH = new GPR8("dh");
    
    /* 16-bit GPR registers */
    public static final GPR16 AX = new GPR16("ax", true);
    public static final GPR16 BX = new GPR16("bx", true);
    public static final GPR16 CX = new GPR16("cx", true);
    public static final GPR16 DX = new GPR16("dx", true);
    public static final GPR16 SP = new GPR16("sp");
    public static final GPR16 BP = new GPR16("bp");
    public static final GPR16 SI = new GPR16("si");
    public static final GPR16 DI = new GPR16("di");
    
    /* 32-bit GPR registers */
    public static final GPR32 EAX = new GPR32("eax", true);
    public static final GPR32 EBX = new GPR32("ebx", true);
    public static final GPR32 ECX = new GPR32("ecx", true);
    public static final GPR32 EDX = new GPR32("edx", true);
    public static final GPR32 ESP = new GPR32("esp");
    public static final GPR32 EBP = new GPR32("ebp");
    public static final GPR32 ESI = new GPR32("esi");
    public static final GPR32 EDI = new GPR32("edi");
    
    /* Segment registers */
    public static final SR ES = new SR("es");
    public static final SR CS = new SR("cs");
    public static final SR SS = new SR("ss");
    public static final SR DS = new SR("ds");
    public static final SR FS = new SR("fs");
    public static final SR GS = new SR("gs");
    
    /* Floating-point registers */
    public static final FPU ST0 = new FPU("st0");
    public static final FPU ST1 = new FPU("st1");
    public static final FPU ST2 = new FPU("st2");
    public static final FPU ST3 = new FPU("st3");
    public static final FPU ST4 = new FPU("st4");
    public static final FPU ST5 = new FPU("st5");
    public static final FPU ST6 = new FPU("st6");
    public static final FPU ST7 = new FPU("st7");
    
    /* MMX registers */
    public static final MMX MM0 = new MMX("mm0");
    public static final MMX MM1 = new MMX("mm1");
    public static final MMX MM2 = new MMX("mm2");
    public static final MMX MM3 = new MMX("mm3");
    public static final MMX MM4 = new MMX("mm4");
    public static final MMX MM5 = new MMX("mm5");
    public static final MMX MM6 = new MMX("mm6");
    public static final MMX MM7 = new MMX("mm7");
    
    /* SSE registers */
    /* For SSE fpu compiler */
    public static final XMM XMM0 = new XMM("xmm0");
    public static final XMM XMM1 = new XMM("xmm1");
    public static final XMM XMM2 = new XMM("xmm2");
    public static final XMM XMM3 = new XMM("xmm3");
    public static final XMM XMM4 = new XMM("xmm4");
    public static final XMM XMM5 = new XMM("xmm5");
    public static final XMM XMM6 = new XMM("xmm6");
    public static final XMM XMM7 = new XMM("xmm7");
    public static final XMM XMM8 = new XMM("xmm8");
    public static final XMM XMM9 = new XMM("xmm9");
    public static final XMM XMM10 = new XMM("xmm10");
    public static final XMM XMM11 = new XMM("xmm11");
    public static final XMM XMM12 = new XMM("xmm12");
    public static final XMM XMM13 = new XMM("xmm13");
    public static final XMM XMM14 = new XMM("xmm14");
    public static final XMM XMM15 = new XMM("xmm15");
	
	private final String name;
	private final int size;
	
	private final boolean suitFor8Bit;

	
	/**
	 * 
	 * @param name Register name.
	 * @param size Register size.
	 */
	public X86Register(String name, int size) {		
		this(name, size, false);
	}
	
	/**
	 * @param name Register name
	 * @param size
	 * @param suitFor8Bit
	 */
	public X86Register(String name, int size, boolean suitFor8Bit) {
		if (name == null) {
			throw new IllegalArgumentException();
		}
		
		this.name = name;
		this.size = size;
		this.suitFor8Bit = suitFor8Bit;
		
		map.put(name, this);
	}

	/**
	 * @return the name
	 */
	public final String getName() {
		return name;
	}

	/**
	 * @return the size
	 */
	public final int getSize() {
		return size;
	}

	/**
	 * @return the suitFor8Bit
	 */
	public final boolean isSuitFor8Bit() {
		return suitFor8Bit;
	}
	
	/**
	 * Get GPR
	 * @return GPR
	 */
	public static GPR getGPR(String name) {
		if (!isGPR(name)) {
			throw new IllegalArgumentException();
		}
		
		return (GPR)map.get(name);
	}
	
	/**
	 * Gets string repr.
	 */
	public final String toString() {
		return getName();
	}
	
	/**
	 * Is GPR.
	 * @return boolean
	 */
	public static boolean isGPR(String name) {
		X86Register reg = map.get(name);
		return ((reg != null) && (reg instanceof GPR));
	}
	
	public static X86Register getRegister(String name) {
		X86Register reg = map.get(name);
		
		if (reg == null) {
			throw new IllegalArgumentException();
		}
		
		return reg;
	}
	
	/**
	 * Represents general-purpose x86 register.
	 * @author Sergey Shulepoff[Knott]
	 */
	public abstract static class GPR extends X86Register {
		
        /**
         * 
         * @param name
         * @param size
         */
        public GPR(String name, int size) {
            super(name, size);
        }
        
        /**
         * 
         * @param name
         * @param size
         * @param suitableFor8Bit
         */
        public GPR(String name, int size, boolean suitableFor8Bit) {
            super(name, size, suitableFor8Bit);
        }
	}
	
	/**
	 * Represents 8bit general purpose x86 register.
	 * @author Sergey Shulepoff[Knott]
	 */
	public static class GPR8 extends GPR {

		/**
		 * @param name
		 * @param suitableFor8Bit
		 */
		public GPR8(String name, boolean suitableFor8Bit) {
			super(name, 8, suitableFor8Bit);
		}

		/**
		 * @param name
		 */
		public GPR8(String name) {
			super(name, 8);
		}
	}
	
	/**
	 * Represents 16bit general purpose x86 register.
	 * @author Sergey Shulepoff[Knott]
	 */
	public static class GPR16 extends GPR {
		
		/**
		 * @param name
		 * @param suitableFor8Bit
		 */
		public GPR16(String name, boolean suitableFor8Bit) {
			super(name, 16, suitableFor8Bit);
		}

		/**
		 * @param name
		 */
		public GPR16(String name) {
			super(name, 16);
		}
	}
	
	/**
	 * Represents 32bit general purpose x86 register.
	 * @author Sergey Shulepoff[Knott]
	 */
	public static class GPR32 extends GPR {
		
		/**
		 * @param name
		 * @param suitableFor8Bit
		 */
		public GPR32(String name, boolean suitableFor8Bit) {
			super(name, 32, suitableFor8Bit);
		}

		/**
		 * @param name
		 */
		public GPR32(String name) {
			super(name, 32);
		}
	}
	
	/**
	 * Represents 80bit floating point unit register.
	 * @author Sergey Shulepoff[Knott]
	 */
	public static final class FPU extends X86Register {
		
		private static int count = 0;
		
		private int number = count++;
		
		/**
		 * @return the number
		 */
		public int getNumber() {
			return number;
		}

		public FPU(String name) {
			super(name, 80);
		}
	}
	
	/**
	 * Represents mmx register.
	 * @author Sergey Shulepoff[Knott]
	 */
	public static final class MMX extends X86Register {
		
		public MMX(String name) {
			super(name, 128, false);
		}
	}
	
	/**
	 * Represents X86 segment register.
	 * @author Sergey Shulepoff[Knott]
	 */
    public static final class SR extends X86Register {
        /**
         * @param name
         * @param nr
         */
        public SR(String name) {
            super(name, 16, false);
        }
    }
    
    /**
     * Represents 128 bit SSE register.
     * @author Sergey Shulepoff[Knott]
     */
    public static final class XMM extends X86Register {

        /**
         * @param name
         */
        public XMM(String name) {
            super(name, 128);
        }
    }
}
